import { Injectable, Logger, BadRequestException, OnModuleInit } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Cron, CronExpression, SchedulerRegistry } from '@nestjs/schedule';
import { CronJob } from 'cron';
import * as fs from 'fs';
import * as path from 'path';
import { FileItem, ViewFilesResponse } from './interfaces/file-item.interface';
import { MatchImportConfig, FileType, ImportFrequency } from './entities/match-import-config.entity';
import { MatchImportRecord, ImportStatus, MatchFileType } from './entities/match-import-record.entity';
import { CreateMatchImportConfigDto } from './dto/create-match-import-config.dto';
import { UpdateMatchImportConfigDto } from './dto/update-match-import-config.dto';
import { ManualImportDto } from './dto/manual-import.dto';
import { QueryImportRecordDto } from './dto/query-import-record.dto';
import { MatchesService } from '../matches/matches.service';

@Injectable()
export class AutomationService implements OnModuleInit {
  private readonly logger = new Logger(AutomationService.name);
  private readonly importingFiles = new Map<string, NodeJS.Timeout>(); // 存储正在导入的文件定时器

  constructor(
    @InjectRepository(MatchImportConfig)
    private readonly configRepository: Repository<MatchImportConfig>,
    @InjectRepository(MatchImportRecord)
    private readonly recordRepository: Repository<MatchImportRecord>,
    private readonly schedulerRegistry: SchedulerRegistry,
    private readonly matchesService: MatchesService,
  ) {}

  /**
   * 模块初始化时设置动态定时任务
   */
  async onModuleInit() {
    await this.setupDynamicCronJobs();
  }

  /**
   * 设置动态定时任务
   */
  private async setupDynamicCronJobs() {
    try {
      // 获取所有启用的配置
      const configs = await this.configRepository.find({
        where: { isEnabled: true }
      });

      // 为每个配置创建定时任务
      for (const config of configs) {
        await this.createCronJobForConfig(config);
      }
    } catch (error) {
      this.logger.error('设置动态定时任务失败', error.stack);
    }
  }

  /**
   * 为配置创建定时任务
   */
  private async createCronJobForConfig(config: MatchImportConfig) {
    const jobName = `import-config-${config.id}`;
    
    // 如果任务已存在，先删除
    try {
      this.schedulerRegistry.deleteCronJob(jobName);
      this.logger.log(`🔄 删除配置${config.id}的旧定时任务`);
    } catch (error) {
      // 任务不存在，忽略错误
    }

    let cronExpression: string;
    let job: CronJob;

    if (config.frequency === ImportFrequency.DAILY) {
      // 每日执行模式: 分钟 小时 * * *
      cronExpression = `${config.importMinute} ${config.importHour} * * *`;
      job = new CronJob(cronExpression, async () => {
        await this.handleDailyImportForConfig(config);
      });
      this.logger.log(`📅 配置${config.id}(${config.name})设置为每日导入模式`);
      this.logger.log(`⏰ 执行时间: 每天 ${String(config.importHour).padStart(2, '0')}:${String(config.importMinute).padStart(2, '0')}`);
    } else {
      // 间隔执行模式: 每N分钟执行一次
      cronExpression = `*/${config.intervalMinutes} * * * *`;
      job = new CronJob(cronExpression, async () => {
        await this.handleIntervalImportForConfig(config);
      });
      this.logger.log(`🔁 配置${config.id}(${config.name})设置为间隔导入模式`);
      this.logger.log(`⏱️ 执行间隔: 每${config.intervalMinutes}分钟`);
    }

    this.logger.log(`📋 文件类型: ${config.fileType === FileType.HOMEPAGE ? '首页文件' : '比分文件'}`);
    this.logger.log(`🔧 重试配置: 最多${config.maxRetries || 6}次，间隔${config.retryIntervalMinutes || 5}分钟`);
    this.logger.log(`📂 导入路径: ${config.importPath}`);
    
    this.schedulerRegistry.addCronJob(jobName, job);
    job.start();
    
    this.logger.log(`✅ 配置${config.id}(${config.fileType})的${config.frequency}模式定时任务创建成功`);
    this.logger.log(`🎯 Cron表达式: ${cronExpression}`);
  }

  /**
   * 删除配置的定时任务
   */
  private deleteCronJobForConfig(configId: number) {
    const jobName = `import-config-${configId}`;
    try {
      this.schedulerRegistry.deleteCronJob(jobName);
      this.logger.log(`删除配置${configId}的定时任务`);
    } catch (error) {
      // 任务不存在，忽略错误
    }
  }

  /**
   * 为特定配置执行每日导入任务
   */
  async handleDailyImportForConfig(config: MatchImportConfig) {
    const currentTime = new Date().toLocaleString('zh-CN');
    this.logger.log(`🚀 [${currentTime}] 定时任务触发 - 开始执行配置${config.id}(${config.name})的每日导入任务`);
    this.logger.log(`📋 任务详情: 文件类型=${config.fileType === FileType.HOMEPAGE ? '首页文件' : '比分文件'}, 导入路径=${config.importPath}`);
    
    try {
      // 重新获取配置以确保是最新的
      const latestConfig = await this.configRepository.findOne({
        where: { id: config.id, isEnabled: true }
      });

      if (!latestConfig) {
        this.logger.warn(`⚠️ 配置${config.id}已被禁用或删除，跳过导入任务`);
        return;
      }

      // 根据文件类型启动对应的导入任务
      if (latestConfig.fileType === FileType.HOMEPAGE) {
        this.logger.log(`📄 开始执行首页文件导入任务...`);
        await this.startHomepageImportTask(latestConfig);
      } else if (latestConfig.fileType === FileType.SCORE) {
        this.logger.log(`⚽ 开始执行比分文件导入任务...`);
        await this.startScoreImportTask(latestConfig);
      }
      
      this.logger.log(`✅ 配置${config.id}(${config.name})的每日导入任务执行完成`);
    } catch (error) {
      this.logger.error(`❌ 执行配置${config.id}的每日导入任务失败`, error.stack);
    }
  }

  /**
   * 为特定配置执行间隔导入任务
   */
  async handleIntervalImportForConfig(config: MatchImportConfig) {
    const currentTime = new Date().toLocaleString('zh-CN');
    this.logger.log(`🔄 [${currentTime}] 定时任务触发 - 开始执行配置${config.id}(${config.name})的间隔导入任务`);
    this.logger.log(`📋 任务详情: 文件类型=${config.fileType === FileType.HOMEPAGE ? '首页文件' : '比分文件'}, 间隔=${config.intervalMinutes}分钟, 导入路径=${config.importPath}`);
    
    try {
      // 重新获取配置以确保是最新的
      const latestConfig = await this.configRepository.findOne({
        where: { id: config.id, isEnabled: true }
      });

      if (!latestConfig) {
        this.logger.warn(`⚠️ 配置${config.id}已被禁用或删除，跳过导入任务`);
        return;
      }

      // 根据文件类型启动对应的导入任务
      if (latestConfig.fileType === FileType.HOMEPAGE) {
        this.logger.log(`📄 开始执行首页文件导入任务...`);
        await this.startHomepageImportTask(latestConfig);
      } else if (latestConfig.fileType === FileType.SCORE) {
        this.logger.log(`⚽ 开始执行比分文件导入任务...`);
        await this.startScoreImportTask(latestConfig);
      }
      
      this.logger.log(`✅ 配置${config.id}(${config.name})的间隔导入任务执行完成`);
    } catch (error) {
      this.logger.error(`❌ 执行配置${config.id}的间隔导入任务失败`, error.stack);
    }
  }

  /**
   * 执行所有配置的定时导入任务（保留用于手动触发）
   */
  async handleDailyImport() {
    this.logger.log('[定时任务启动] 开始执行每日定时导入任务');
    
    let configs: MatchImportConfig[] = [];
    try {
      // 获取所有启用的配置
      configs = await this.configRepository.find({
        where: { isEnabled: true }
      });

      if (configs.length === 0) {
        this.logger.warn('[配置检查] 没有找到启用的导入配置');
        return;
      }

      // 为每个配置启动首页和比分文件导入任务
      for (const config of configs) {
        await Promise.all([
          this.startHomepageImportTask(config),
          this.startScoreImportTask(config)
        ]);
      }
    } catch (error) {
      this.logger.error(`[定时任务执行失败] 每日定时导入任务执行异常, 异常原因: ${error.message}, 启用配置数量: ${configs?.length || 0}`, error.stack);
    }
  }

  /**
   * 启动首页文件导入任务（带重试机制）
   */
  private async startHomepageImportTask(config: MatchImportConfig) {
    const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD格式
    const fileName = `${today}竞彩北单首页.xlsx`;
    const filePath = path.join(config.importPath, fileName);
    const taskKey = `${config.id}-${today}-homepage`;

    // 如果已经在导入中，跳过
    if (this.importingFiles.has(taskKey)) {
      this.logger.warn(`[任务跳过] 配置ID: ${config.id}, 文件: ${fileName}, 原因: 首页文件导入任务已在进行中`);
      return;
    }

    this.logger.log(`[任务启动] 配置ID: ${config.id}, 文件类型: 首页文件, 文件名: ${fileName}, 最大重试次数: ${config.maxRetries || 6}`);
    
    let retryCount = 0;
     const maxRetries = config.maxRetries || 6;
     const retryInterval = (config.retryIntervalMinutes || 5) * 60 * 1000; // 配置的重试间隔（分钟）

    const tryImport = async () => {
      try {
        const success = await this.importHomepageFile(config, filePath, fileName, today);
        
        if (success) {
          this.logger.log(`[导入成功] 配置ID: ${config.id}, 文件类型: 首页文件, 文件名: ${fileName}, 重试次数: ${retryCount}`);
          // 清除失败原因
          await this.updateConfigFailureReason(config.id, null);
          this.importingFiles.delete(taskKey);
          return;
        }
        
        retryCount++;
        if (retryCount < maxRetries) {
          this.logger.warn(`[导入失败] 配置ID: ${config.id}, 文件: ${fileName}, 失败原因: 文件不存在或处理失败, 重试次数: ${retryCount}/${maxRetries}, ${retryInterval/1000/60}分钟后进行第${retryCount + 1}次重试`);
          const timer = setTimeout(tryImport, retryInterval);
          this.importingFiles.set(taskKey, timer);
        } else {
          const failureReason = `首页文件导入失败，已达到最大重试次数${maxRetries}次，文件路径: ${filePath}`;
          this.logger.error(`[导入最终失败] 配置ID: ${config.id}, 文件: ${fileName}, 失败原因: ${failureReason}, 总重试次数: ${maxRetries}`);
          // 更新配置的失败原因
          await this.updateConfigFailureReason(config.id, failureReason);
          this.importingFiles.delete(taskKey);
        }
      } catch (error) {
        retryCount++;
        if (retryCount < maxRetries) {
          this.logger.error(`[导入异常] 配置ID: ${config.id}, 文件: ${fileName}, 异常原因: ${error.message}, 重试次数: ${retryCount}/${maxRetries}, ${retryInterval/1000/60}分钟后重试`, error.stack);
          const timer = setTimeout(tryImport, retryInterval);
          this.importingFiles.set(taskKey, timer);
        } else {
          const failureReason = `首页文件导入异常，已达到最大重试次数${maxRetries}次，错误信息: ${error.message}`;
          this.logger.error(`[导入最终异常] 配置ID: ${config.id}, 文件: ${fileName}, 异常原因: ${failureReason}, 总重试次数: ${maxRetries}`, error.stack);
          // 更新配置的失败原因
          await this.updateConfigFailureReason(config.id, failureReason);
          this.importingFiles.delete(taskKey);
        }
      }
    };

    // 立即执行第一次导入
    await tryImport();
  }

  /**
   * 启动比分文件导入任务（带重试机制）
   */
  private async startScoreImportTask(config: MatchImportConfig) {
    const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD格式
    const fileName = `${today}竞彩北单比分.xlsx`;
    const filePath = path.join(config.importPath, fileName);
    const taskKey = `${config.id}-${today}-score`;

    // 如果已经在导入中，跳过
    if (this.importingFiles.has(taskKey)) {
      this.logger.warn(`[任务跳过] 配置ID: ${config.id}, 文件: ${fileName}, 原因: 比分文件导入任务已在进行中`);
      return;
    }

    this.logger.log(`[任务启动] 配置ID: ${config.id}, 文件类型: 比分文件, 文件名: ${fileName}, 最大重试次数: ${config.maxRetries || 6}`);
    
    let retryCount = 0;
     const maxRetries = config.maxRetries || 6;
     const retryInterval = (config.retryIntervalMinutes || 5) * 60 * 1000; // 配置的重试间隔（分钟）

    const tryImport = async () => {
      try {
        const success = await this.importScoreFile(config, filePath, fileName, today);
        
        if (success) {
          this.logger.log(`[导入成功] 配置ID: ${config.id}, 文件类型: 比分文件, 文件名: ${fileName}, 重试次数: ${retryCount}`);
          // 清除失败原因
          await this.updateConfigFailureReason(config.id, null);
          this.importingFiles.delete(taskKey);
          return;
        }
        
        retryCount++;
        if (retryCount < maxRetries) {
          this.logger.warn(`[导入失败] 配置ID: ${config.id}, 文件: ${fileName}, 失败原因: 文件不存在或处理失败, 重试次数: ${retryCount}/${maxRetries}, ${retryInterval/1000/60}分钟后进行第${retryCount + 1}次重试`);
          const timer = setTimeout(tryImport, retryInterval);
          this.importingFiles.set(taskKey, timer);
        } else {
          const failureReason = `比分文件导入失败，已达到最大重试次数${maxRetries}次，文件路径: ${filePath}`;
          this.logger.error(`[导入最终失败] 配置ID: ${config.id}, 文件: ${fileName}, 失败原因: ${failureReason}, 总重试次数: ${maxRetries}`);
          // 更新配置的失败原因
          await this.updateConfigFailureReason(config.id, failureReason);
          this.importingFiles.delete(taskKey);
        }
      } catch (error) {
        retryCount++;
        if (retryCount < maxRetries) {
          this.logger.error(`[导入异常] 配置ID: ${config.id}, 文件: ${fileName}, 异常原因: ${error.message}, 重试次数: ${retryCount}/${maxRetries}, ${retryInterval/1000/60}分钟后重试`, error.stack);
          const timer = setTimeout(tryImport, retryInterval);
          this.importingFiles.set(taskKey, timer);
        } else {
          const failureReason = `比分文件导入异常，已达到最大重试次数${maxRetries}次，错误信息: ${error.message}`;
          this.logger.error(`[导入最终异常] 配置ID: ${config.id}, 文件: ${fileName}, 异常原因: ${failureReason}, 总重试次数: ${maxRetries}`, error.stack);
          // 更新配置的失败原因
          await this.updateConfigFailureReason(config.id, failureReason);
          this.importingFiles.delete(taskKey);
        }
      }
    };

    // 立即执行第一次导入
    await tryImport();
  }

  /**
   * 导入首页文件
   */
  private async importHomepageFile(config: MatchImportConfig, filePath: string, fileName: string, fileDate: string): Promise<boolean> {
    try {
      // 检查文件是否存在
      if (!fs.existsSync(filePath)) {
        this.logger.error(`[文件检查失败] 配置ID: ${config.id}, 文件: ${fileName}, 失败原因: 文件不存在, 文件路径: ${filePath}`);
        await this.createImportRecord(config.id, fileName, filePath, MatchFileType.HOMEPAGE, ImportStatus.FAILED, '文件不存在', fileDate);
        return false;
      }

      // 检查是否已经导入过
      const existingRecord = await this.recordRepository.findOne({
        where: {
          configId: config.id,
          fileName,
          fileType: MatchFileType.HOMEPAGE,
          status: ImportStatus.SUCCESS
        }
      });

      if (existingRecord) {
        this.logger.log(`[文件跳过] 配置ID: ${config.id}, 文件: ${fileName}, 原因: 首页文件已经导入过`);
        return true;
      }

      // 创建处理中记录
      const record = await this.createImportRecord(config.id, fileName, filePath, MatchFileType.HOMEPAGE, ImportStatus.PROCESSING, undefined, fileDate);

      // 这里应该调用实际的文件处理逻辑
      // 目前先模拟处理过程
      const success = await this.processMatchFile(filePath, MatchFileType.HOMEPAGE);

      if (success) {
        // 更新记录为成功
        await this.recordRepository.update(record.id, {
          status: ImportStatus.SUCCESS
        });
        return true;
      } else {
        // 更新记录为失败
        this.logger.error(`[文件处理失败] 配置ID: ${config.id}, 文件: ${fileName}, 失败原因: 文件处理失败, 记录ID: ${record.id}`);
        await this.recordRepository.update(record.id, {
          status: ImportStatus.FAILED,
          errorMessage: '文件处理失败'
        });
        return false;
      }
    } catch (error) {
      this.logger.error(`[导入首页文件异常] 配置ID: ${config.id}, 文件: ${fileName}, 异常原因: ${error.message}, 文件路径: ${filePath}`, error.stack);
      await this.createImportRecord(config.id, fileName, filePath, MatchFileType.HOMEPAGE, ImportStatus.FAILED, error.message, fileDate);
      return false;
    }
  }

  /**
   * 导入比分文件
   */
  private async importScoreFile(config: MatchImportConfig, filePath: string, fileName: string, fileDate: string): Promise<boolean> {
    try {
      // 检查文件是否存在
      if (!fs.existsSync(filePath)) {
        this.logger.error(`[文件检查失败] 配置ID: ${config.id}, 文件: ${fileName}, 失败原因: 文件不存在, 文件路径: ${filePath}`);
        await this.createImportRecord(config.id, fileName, filePath, MatchFileType.SCORE, ImportStatus.FAILED, '文件不存在', fileDate);
        return false;
      }

      // 检查是否已经导入过
      const existingRecord = await this.recordRepository.findOne({
        where: {
          configId: config.id,
          fileName,
          fileType: MatchFileType.SCORE,
          status: ImportStatus.SUCCESS
        }
      });

      if (existingRecord) {
        this.logger.log(`[文件跳过] 配置ID: ${config.id}, 文件: ${fileName}, 原因: 比分文件已经导入过`);
        return true;
      }

      // 创建处理中记录
      const record = await this.createImportRecord(config.id, fileName, filePath, MatchFileType.SCORE, ImportStatus.PROCESSING, undefined, fileDate);

      // 这里应该调用实际的文件处理逻辑
      // 目前先模拟处理过程
      const success = await this.processMatchFile(filePath, MatchFileType.SCORE);

      if (success) {
        // 更新记录为成功
        await this.recordRepository.update(record.id, {
          status: ImportStatus.SUCCESS
        });
        return true;
      } else {
        // 更新记录为失败
        this.logger.error(`[文件处理失败] 配置ID: ${config.id}, 文件: ${fileName}, 失败原因: 文件处理失败, 记录ID: ${record.id}`);
        await this.recordRepository.update(record.id, {
          status: ImportStatus.FAILED,
          errorMessage: '文件处理失败'
        });
        return false;
      }
    } catch (error) {
      this.logger.error(`[导入比分文件异常] 配置ID: ${config.id}, 文件: ${fileName}, 异常原因: ${error.message}, 文件路径: ${filePath}`, error.stack);
      await this.createImportRecord(config.id, fileName, filePath, MatchFileType.SCORE, ImportStatus.FAILED, error.message, fileDate);
      return false;
    }
  }

  /**
   * 处理比赛文件（这里需要根据实际业务逻辑实现）
   */
  private async processMatchFile(filePath: string, fileType: MatchFileType): Promise<boolean> {
    try {
      // 检查文件是否存在
      if (!fs.existsSync(filePath)) {
        return false;
      }

      // 读取文件内容
      const fileBuffer = fs.readFileSync(filePath);

      // 根据文件类型调用不同的导入方法
      let importResult;
      if (fileType === MatchFileType.HOMEPAGE) {
        // 首页文件导入 - 创建新比赛数据
        importResult = await this.matchesService.importExcel(fileBuffer);
      } else if (fileType === MatchFileType.SCORE) {
        // 比分文件导入 - 更新比赛比分
        importResult = await this.matchesService.importScoreUpdate(fileBuffer);
      } else {
        return false;
      }

      // 检查导入结果
      return importResult.isSuccess;
    } catch (error) {
      this.logger.error(`[文件处理异常] 文件类型: ${fileType}, 文件路径: ${filePath}, 异常原因: ${error.message}`, error.stack);
      return false;
    }
  }

  /**
   * 创建导入记录
   */
  private async createImportRecord(
    configId: number,
    fileName: string,
    filePath: string,
    fileType: MatchFileType,
    status: ImportStatus,
    errorMessage?: string,
    fileDate?: string
  ): Promise<MatchImportRecord> {
    const recordData: Partial<MatchImportRecord> = {
      configId,
      fileName,
      filePath,
      fileType,
      status,
      errorMessage,
      fileDate: fileDate ? new Date(fileDate) : undefined
    };

    const record = this.recordRepository.create(recordData);
    return await this.recordRepository.save(record);
  }

  /**
   * 手动导入比分文件
   */
  async manualImportScore(dto: ManualImportDto): Promise<MatchImportRecord> {
    const config = await this.configRepository.findOne({
      where: { id: parseInt(dto.configId) }
    });

    if (!config) {
      throw new BadRequestException('配置不存在');
    }

    const fileDate = dto.fileDate || new Date().toISOString().split('T')[0];
    const fileName = `${fileDate}竞彩北单比分.xlsx`;
    const filePath = dto.customFilePath || path.join(config.importPath, fileName);

    try {
      // 检查文件是否存在
      if (!fs.existsSync(filePath)) {
        throw new BadRequestException('指定的比分文件不存在');
      }

      // 创建处理中记录
      const record = await this.createImportRecord(
        config.id,
        fileName,
        filePath,
        MatchFileType.SCORE,
        ImportStatus.PROCESSING,
        undefined,
        fileDate
      );

      // 处理文件
      const success = await this.processMatchFile(filePath, MatchFileType.SCORE);

      if (success) {
        await this.recordRepository.update(record.id, {
          status: ImportStatus.SUCCESS
        });
        this.logger.log(`[手动导入成功] 配置ID: ${config.id}, 文件类型: 比分文件, 文件名: ${fileName}, 记录ID: ${record.id}`);
      } else {
        this.logger.error(`[手动导入失败] 配置ID: ${config.id}, 文件: ${fileName}, 失败原因: 比分文件处理失败, 记录ID: ${record.id}`);
        await this.recordRepository.update(record.id, {
          status: ImportStatus.FAILED,
          errorMessage: '文件处理失败'
        });
        throw new BadRequestException('比分文件处理失败');
      }

      const updatedRecord = await this.recordRepository.findOne({ where: { id: record.id } });
      if (!updatedRecord) {
        throw new BadRequestException('导入记录未找到');
      }
      return updatedRecord;
    } catch (error) {
      this.logger.error(`[手动导入比分文件异常] 配置ID: ${config.id}, 文件: ${fileName}, 异常原因: ${error.message}, 文件路径: ${filePath}`, error.stack);
      if (error instanceof BadRequestException) {
        throw error;
      }
      throw new BadRequestException(`导入失败: ${error.message}`);
    }
  }

  /**
   * 手动导入单个首页文件
   */
  async manualImportHomepage(dto: ManualImportDto): Promise<MatchImportRecord> {
    const config = await this.configRepository.findOne({
      where: { id: parseInt(dto.configId) }
    });

    if (!config) {
      throw new BadRequestException('配置不存在');
    }

    const fileDate = dto.fileDate || new Date().toISOString().split('T')[0];
    const fileName = `${fileDate}竞彩北单首页.xlsx`;
    const filePath = dto.customFilePath || path.join(config.importPath, fileName);

    try {
      // 检查文件是否存在
      if (!fs.existsSync(filePath)) {
        throw new BadRequestException('指定的首页文件不存在');
      }

      // 创建处理中记录
      const record = await this.createImportRecord(
        config.id,
        fileName,
        filePath,
        MatchFileType.HOMEPAGE,
        ImportStatus.PROCESSING,
        undefined,
        fileDate
      );

      // 处理文件
      const success = await this.processMatchFile(filePath, MatchFileType.HOMEPAGE);

      if (success) {
        await this.recordRepository.update(record.id, {
          status: ImportStatus.SUCCESS
        });
        this.logger.log(`[手动导入成功] 配置ID: ${config.id}, 文件类型: 首页文件, 文件名: ${fileName}, 记录ID: ${record.id}`);
      } else {
        this.logger.error(`[手动导入失败] 配置ID: ${config.id}, 文件: ${fileName}, 失败原因: 首页文件处理失败, 记录ID: ${record.id}`);
        await this.recordRepository.update(record.id, {
          status: ImportStatus.FAILED,
          errorMessage: '文件处理失败'
        });
        throw new BadRequestException('首页文件处理失败');
      }

      const updatedRecord = await this.recordRepository.findOne({ where: { id: record.id } });
      if (!updatedRecord) {
        throw new BadRequestException('导入记录未找到');
      }
      return updatedRecord;
    } catch (error) {
      this.logger.error(`[手动导入首页文件异常] 配置ID: ${config.id}, 文件: ${fileName}, 异常原因: ${error.message}, 文件路径: ${filePath}`, error.stack);
      if (error instanceof BadRequestException) {
        throw error;
      }
      throw new BadRequestException(`导入失败: ${error.message}`);
    }
  }

  /**
   * 手动触发所有配置的比分文件导入任务
   */
  async triggerAllScoreImport() {
    this.logger.log('[手动触发] 开始手动触发所有配置的比分文件导入任务');
    
    let configs: MatchImportConfig[] = [];
    try {
      // 获取所有启用的配置
      configs = await this.configRepository.find({
        where: { isEnabled: true }
      });

      if (configs.length === 0) {
        this.logger.warn('[配置检查] 没有找到启用的导入配置');
        return;
      }

      // 为每个配置启动比分文件导入任务
      for (const config of configs) {
        await this.startScoreImportTask(config);
      }
    } catch (error) {
      this.logger.error(`[手动触发失败] 手动触发所有配置的比分文件导入任务异常, 异常原因: ${error.message}, 启用配置数量: ${configs?.length || 0}`, error.stack);
    }
  }

  /**
   * 创建导入配置
   */
  async createConfig(dto: CreateMatchImportConfigDto): Promise<MatchImportConfig> {
    this.logger.log(`🆕 开始创建新的导入配置: ${dto.name}`);
    this.logger.log(`📋 配置详情: ${JSON.stringify(dto)}`);
    
    // 检查导入路径是否存在
    if (!fs.existsSync(dto.importPath)) {
      this.logger.error(`❌ 导入路径不存在: ${dto.importPath}`);
      throw new BadRequestException('指定的导入路径不存在');
    }
    this.logger.log(`✅ 导入路径验证通过: ${dto.importPath}`);

    const config = this.configRepository.create({
      ...dto,
      isEnabled: dto.isEnabled ?? true,
      importHour: dto.importHour ?? 12,
      importMinute: dto.importMinute ?? 35
    });

    const savedConfig = await this.configRepository.save(config);
    this.logger.log(`💾 配置已保存到数据库，ID: ${savedConfig.id}`);
    
    // 如果配置启用，创建定时任务
    if (savedConfig.isEnabled) {
      this.logger.log(`🚀 配置已启用，正在创建定时任务...`);
      await this.createCronJobForConfig(savedConfig);
    } else {
      this.logger.log(`⏸️ 配置已创建但未启用，跳过定时任务创建`);
    }
    
    this.logger.log(`🎉 配置${savedConfig.id}(${savedConfig.name})创建完成`);
    return savedConfig;
  }

  /**
   * 获取所有配置
   */
  async getAllConfigs(): Promise<MatchImportConfig[]> {
    return await this.configRepository.find({
      order: { createdAt: 'DESC' }
    });
  }

  /**
   * 获取单个配置
   */
  async getConfig(id: number): Promise<MatchImportConfig> {
    const config = await this.configRepository.findOne({ where: { id } });
    if (!config) {
      throw new BadRequestException('配置不存在');
    }
    return config;
  }

  /**
   * 更新配置
   */
  async updateConfig(id: number, dto: UpdateMatchImportConfigDto): Promise<MatchImportConfig> {
    const config = await this.getConfig(id);
    
    this.logger.log(`开始更新配置${id}: ${config.name}`);
    this.logger.log(`更新内容: ${JSON.stringify(dto)}`);
    
    // 如果更新了导入路径，检查路径是否存在
    if (dto.importPath && dto.importPath !== config.importPath) {
      if (!fs.existsSync(dto.importPath)) {
        throw new BadRequestException('指定的导入路径不存在');
      }
    }

    await this.configRepository.update(id, dto);
    const updatedConfig = await this.getConfig(id);
    
    // 删除旧的定时任务
    this.deleteCronJobForConfig(id);
    
    // 如果配置启用，创建新的定时任务
    if (updatedConfig.isEnabled) {
      this.logger.log(`配置${id}已启用，正在重新创建定时任务...`);
      await this.createCronJobForConfig(updatedConfig);
      this.logger.log(`✅ 配置${id}(${updatedConfig.name})的定时任务已成功更新`);
    } else {
      this.logger.log(`❌ 配置${id}已禁用，定时任务已删除`);
    }
    
    this.logger.log(`🎉 配置${id}(${updatedConfig.name})更新完成`);
    return updatedConfig;
  }

  /**
   * 删除配置
   */
  async deleteConfig(id: number): Promise<void> {
    const config = await this.getConfig(id);
    
    this.logger.log(`🗑️ 开始删除配置${id}: ${config.name}`);
    this.logger.log(`📋 配置信息: 文件类型=${config.fileType}, 频率=${config.frequency}, 路径=${config.importPath}`);
    
    // 删除对应的定时任务
    this.deleteCronJobForConfig(id);
    this.logger.log(`✅ 配置${id}的定时任务已删除`);
    
    await this.configRepository.remove(config);
    this.logger.log(`🎉 配置${id}(${config.name})删除完成`);
  }

  /**
   * 获取导入记录
   */
  async getImportRecords(dto: QueryImportRecordDto) {
    const { page = 1, limit = 10, fileType, status, configId, fileName } = dto;
    const skip = (page - 1) * limit;

    const queryBuilder = this.recordRepository.createQueryBuilder('record')
      .leftJoinAndSelect('record.config', 'config')
      .orderBy('record.importTime', 'DESC')
      .skip(skip)
      .take(limit);

    if (fileType) {
      queryBuilder.andWhere('record.fileType = :fileType', { fileType });
    }

    if (status) {
      queryBuilder.andWhere('record.status = :status', { status });
    }

    if (configId) {
      queryBuilder.andWhere('record.configId = :configId', { configId });
    }

    if (fileName) {
      queryBuilder.andWhere('record.fileName LIKE :fileName', { fileName: `%${fileName}%` });
    }

    const [records, total] = await queryBuilder.getManyAndCount();

    return {
      records,
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit)
    };
  }

  /**
   * 查看指定路径下的文件和目录
   */
  async viewFiles(filePath: string, recursive: boolean = false, showHidden: boolean = false): Promise<ViewFilesResponse> {
    try {
      // 验证路径是否存在
      if (!fs.existsSync(filePath)) {
        throw new BadRequestException('指定的路径不存在');
      }

      const stats = fs.statSync(filePath);
      
      // 如果是文件，返回文件信息
      if (stats.isFile()) {
        return {
          type: 'file',
          name: path.basename(filePath),
          path: filePath,
          size: stats.size,
          modifiedTime: stats.mtime,
          isDirectory: false
        };
      }

      // 如果是目录，返回目录内容
      if (stats.isDirectory()) {
        const items = await this.getDirectoryContents(filePath, recursive, showHidden);
        return {
          type: 'directory',
          name: path.basename(filePath),
          path: filePath,
          modifiedTime: stats.mtime,
          items,
          totalCount: items.length,
          isDirectory: true
        };
      }

      throw new BadRequestException('指定的路径既不是文件也不是目录');
    } catch (error) {
      this.logger.error(`查看文件失败: ${error.message}`, error.stack);
      if (error instanceof BadRequestException) {
        throw error;
      }
      throw new BadRequestException(`查看文件失败: ${error.message}`);
    }
  }

  /**
   * 更新配置的失败原因
   */
  private async updateConfigFailureReason(configId: number, failureReason: string | null): Promise<void> {
    try {
      const updateData = failureReason ? { failureReason } : { failureReason: undefined };
      await this.configRepository.update(configId, updateData);
      if (failureReason) {
        this.logger.log(`📝 已更新配置${configId}的失败原因: ${failureReason}`);
      } else {
        this.logger.log(`✅ 已清除配置${configId}的失败原因`);
      }
    } catch (error) {
      this.logger.error(`更新配置${configId}失败原因时出错: ${error.message}`, error.stack);
    }
  }

  /**
   * 获取目录内容
   */
  private async getDirectoryContents(dirPath: string, recursive: boolean, showHidden: boolean): Promise<FileItem[]> {
    const items: FileItem[] = [];
    const files = fs.readdirSync(dirPath);

    for (const file of files) {
      // 如果不显示隐藏文件且文件名以.开头，跳过
      if (!showHidden && file.startsWith('.')) {
        continue;
      }

      const filePath = path.join(dirPath, file);
      const stats = fs.statSync(filePath);

      const item: FileItem = {
        name: file,
        path: filePath,
        isDirectory: stats.isDirectory(),
        size: stats.isFile() ? stats.size : null,
        modifiedTime: stats.mtime,
        type: stats.isDirectory() ? 'directory' : 'file'
      };

      // 如果是目录且需要递归，获取子目录内容
      if (recursive && stats.isDirectory()) {
        try {
          item['children'] = await this.getDirectoryContents(filePath, recursive, showHidden);
        } catch (error) {
          // 如果无法访问子目录（权限问题等），记录错误但不中断
          this.logger.warn(`无法访问子目录 ${filePath}: ${error.message}`);
          item['children'] = [];
          item['error'] = '无法访问';
        }
      }

      items.push(item);
    }

    // 按类型和名称排序：目录在前，文件在后，同类型按名称排序
    return items.sort((a, b) => {
      if (a.isDirectory && !b.isDirectory) return -1;
      if (!a.isDirectory && b.isDirectory) return 1;
      return a.name.localeCompare(b.name);
    });
  }
}